package cn.jdemo.io.inpustream;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @see InputStream 抽象基类
 * @see java.io.FileInputStream
 * (1)实例化需要byte[]
 * (2)也支持mark(标记)
 * (3)也支持skip
 *
 * // 构造方法
 * @see FileInputStream#FileInputStream(File file) 要读取的文件
 * @see FileInputStream#FileInputStream(String name) 与系统有关的文件名
 * @see FileInputStream#FileInputStream(FileDescriptor fdObj) FileDescriptor是"文件描述符";
 *
 * // 包含inputstream常用方法
 *
 * // 有别于其他的方法，实现了DataInput的方法
 * @see FileInputStream#getFD() 获取文件描述符
 * @see FileInputStream#available() 剩余字节数的估计:在不阻塞的情况下可以从此输入流读取（或跳过）的剩余字节数的估计
 * @see FileInputStream#open(String) 反射调用open,可以打开新的文件流
 * @see FileInputStream#open0(String) 反射调用open0,可以打开新的文件流
 *
 * @date 2020/12/21
 */
public class Demo04_FileInputStream {
    public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        // test01();
        test02();
    }

    public static void test01() throws IOException {
        FileInputStream fileIS = new FileInputStream("D:\\test.txt");// 文件名
        byte[] bs = new byte[1024];
        int read = fileIS.read(bs);
        System.out.println(new String(bs));
        fileIS.close();
    }

    /**
     * 问题:FileInputStream 在使用完以后，不关闭流，想二次使用可以怎么操作?
     * 反射调用私有方法，在流没有关闭的情况下，重新读取文件
     * @see FileInputStream#open(String) 
     * @see FileInputStream#open0(String)
     *
     * @throws IOException
     */
    public static void test02() throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        FileInputStream fileIS = new FileInputStream("D:\\test.txt");

        // 反射调用open()/open0()方法,重新处理新的文件
        Class<? extends FileInputStream> aClass = fileIS.getClass();
        Method open0 = aClass.getDeclaredMethod("open0", String.class);
        open0.setAccessible(true);
        open0.invoke(fileIS,"D:\\1.txt");

        byte[] bs = new byte[1024];
        int read = fileIS.read(bs);
        System.out.println(new String(bs));
        fileIS.close();
    }

    public static void test03() throws IOException {
        FileInputStream fileIS = new FileInputStream(FileDescriptor.in);
        byte[] bs = new byte[1024];
        int read = fileIS.read(bs);
        System.out.println(new String(bs));
        fileIS.close();
    }

    /**
     *  public void testFileinp() throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
     *         FileInputStream inputStream=new FileInputStream("E:/test/te.txt");
     *         FileOutputStream outputStream=new FileOutputStream("E:/test/te2.txt");
     *         FileOutputStream outputStreams=new FileOutputStream("E:/test/te3.txt");
     *         int len;
     *         byte [] by=new byte[8192];
     *         while ((len=inputStream.read(by))!=-1){
     *             outputStream.write(by,0,len);
     *         }
     *         if(inputStream.read()==-1){
     *             Class in=inputStream.getClass();
     *             Method openo= in.getDeclaredMethod("open0", String.class);
     *             openo.setAccessible(true);
     *             openo.invoke(inputStream,"E:/test/te.txt");
     *         }
     *         while ((len=inputStream.read(by))!=-1){
     *             outputStreams.write(by,0,len);
     *         }
     *         outputStream.close();
     */

    /**
     * FileDescriptor详解
     * FileDescriptor是"文件描述符".
     *
     * FileDescriptor可以被用来表示开放的文件,开放的套接字等.
     *
     * 当FileDescriptor表示文件来说,当FIleDescriptor表示某文件时,我们可以通俗的将FIleDescriptor看成该文件.
     * 但是,我们不能直接通过FIleDescriptor对该文件进行操作;
     * 若需要通过FIleDescriptor对该文件进行操作,则需要创建FileDescriptor对应的FileOutputStream,再对文件进行操作.
     *
     * in,out,err的介绍
     *  in:标准输入(键盘)的描述符
     * out:标准输出(屏幕)的描述符
     * err:标准错误输出(屏幕)的描述符
     * 他们三个的原理和用法都类似,下面通过out来进行深入的研究
     *
     * out的作用和原理
     * out时标准输出(屏幕)的描述符,但是他有什么作用呢?
     *
     * 我们可以通俗理解,out 就代表了标准输出(屏幕).如我们要输出信息到屏幕,既可以通过out来操作,但是,out 有没有提供输出信息到屏幕的接口,怎么办呢?
     *
     * 很简单,我们创建Out对应的"输出流对象",然后通过"输出流"的write()等接口就可以输出信息到屏幕上去了.
     *
     * 复制代码
     * 1 public static void main(String[] args) throws IOException
     * 2     {
     * 3         FileOutputStream out = new FileOutputStream(java.io.FileDescriptor.out);
     * 4         out.write("你好啊!".getBytes());
     * 5         out.close();
     * 6     }
     * 复制代码
     *
     *
     * 程序输出:你好啊!
     *
     * 为了方便我们的操作,java早已经为我们封装好了能再屏幕上输出信息的接口:通过System.out
     *
     * 因此上面的代码等同于:System.out.print("你好啊!").
     */

}
